package com.michale.framework.config.mybatisscan;

import com.baomidou.mybatisplus.core.config.GlobalConfig;
import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
import com.baomidou.mybatisplus.extension.spring.MybatisSqlSessionFactoryBean;
import com.michale.common.properties.MybatisProperties;
import com.michale.common.utils.String.StringUtils;
import org.apache.ibatis.io.VFS;
import org.apache.ibatis.session.SqlSessionFactory;
import org.mybatis.spring.boot.autoconfigure.SpringBootVFS;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.DefaultResourceLoader;
import org.springframework.core.io.Resource;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.core.io.support.ResourcePatternResolver;
import org.springframework.core.type.classreading.CachingMetadataReaderFactory;
import org.springframework.core.type.classreading.MetadataReader;
import org.springframework.core.type.classreading.MetadataReaderFactory;
import org.springframework.util.ClassUtils;

import javax.sql.DataSource;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;

/**
 * @author Michale
 * @apiNote Mybatis支持*匹配扫描包
 */
@Configuration
public class MyBatisConfig {

    @Autowired
    private MybatisProperties mybatisProperties;
    static final String DEFAULT_RESOURCE_PATTERN = "**/*.class";
    @Autowired
    private MybatisPlusInterceptor mybatisPlusInterceptor;
    @Autowired
    private GlobalConfig globalConfig;

    @Bean("sqlSessionFactory")
    public SqlSessionFactory sqlSessionFactory(DataSource dataSource) throws Exception {
        /* 获取配置信息 */
        String typeAliasesPackage = mybatisProperties.getTypeAliasesPackage();
        String mapperLocations = mybatisProperties.getMapperLocations();
        String configLocation = mybatisProperties.getConfigLocation();
        typeAliasesPackage = setTypeAliasesPackage(typeAliasesPackage);
        /* 将指定的类添加到VFS实现列表中 */
        VFS.addImplClass(SpringBootVFS.class);

        /* 依赖Spring容器完成MyBatis的SqlSessionFactory对象的创建 */
        final MybatisSqlSessionFactoryBean sessionFactoryBean = new MybatisSqlSessionFactoryBean();
        /* 配置数据源 */
        sessionFactoryBean.setDataSource(dataSource);
        /* 配置需要定义别名的实体类的包 */
        sessionFactoryBean.setTypeAliasesPackage(typeAliasesPackage);
        /* 配置mapper文件的路径 */
        sessionFactoryBean.setMapperLocations(resolveMapperLocations(StringUtils.split(mapperLocations, ",")));
        /* 配置mybatis配置文件的路径 */
        sessionFactoryBean.setConfigLocation(new DefaultResourceLoader().getResource(configLocation));
        sessionFactoryBean.setPlugins(mybatisPlusInterceptor);
        sessionFactoryBean.setGlobalConfig(globalConfig);
        return sessionFactoryBean.getObject();
    }

    /**
     * typeAliasesPackage 路径扫描
     *
     * @param typeAliasesPackage 路径
     */
    public static String setTypeAliasesPackage(String typeAliasesPackage) {
        ResourcePatternResolver resolver = new PathMatchingResourcePatternResolver();
        MetadataReaderFactory metadataReaderFactory = new CachingMetadataReaderFactory(resolver);
        List<String> allResult = new ArrayList<>();
        try {
            for (String aliasesPackage : typeAliasesPackage.split(",")) {
                List<String> result = new ArrayList<>();
                aliasesPackage = ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX
                        + ClassUtils.convertClassNameToResourcePath(aliasesPackage.trim()) + "/" + DEFAULT_RESOURCE_PATTERN;
                Resource[] resources = resolver.getResources(aliasesPackage);
                if (resources != null && resources.length > 0) {
                    MetadataReader metadataReader;
                    for (Resource resource : resources) {
                        if (resource.isReadable()) {
                            metadataReader = metadataReaderFactory.getMetadataReader(resource);
                            try {
                                result.add(Class.forName(metadataReader.getClassMetadata().getClassName()).getPackage().getName());
                            } catch (ClassNotFoundException e) {
                                e.printStackTrace();
                            }
                        }
                    }
                }
                if (result.size() > 0) {
                    HashSet<String> hashResult = new HashSet<>(result);
                    allResult.addAll(hashResult);
                }
            }
            if (allResult.size() > 0) {
                typeAliasesPackage = String.join(",", allResult.toArray(new String[0]));
            } else {
                throw new RuntimeException("mybatis typeAliasesPackage 路径扫描错误,参数typeAliasesPackage:" + typeAliasesPackage + "未找到任何包");
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
        return typeAliasesPackage;
    }

    /**
     * mybatisProperties 路径扫描
     *
     * @param mapperLocations 路径
     */
    public Resource[] resolveMapperLocations(String[] mapperLocations) {
        ResourcePatternResolver resourceResolver = new PathMatchingResourcePatternResolver();
        List<Resource> resources = new ArrayList<>();
        if (mapperLocations != null) {
            for (String mapperLocation : mapperLocations) {
                try {
                    Resource[] mappers = resourceResolver.getResources(mapperLocation);
                    resources.addAll(Arrays.asList(mappers));
                } catch (IOException e) {
                    // ignore
                }
            }
        }
        return resources.toArray(new Resource[resources.size()]);
    }


}
